package org.bitterorange.flansmodslain;

import com.flansmod.common.blocks.BlockAPI;
import com.flansmod.common.guns.type.BulletType;
import com.flansmod.common.guns.type.GrenadeType;
import com.flansmod.common.hook.MCHeliUtil;
import com.flansmod.common.mob.api.SoldierAPI;
import com.flansmod.common.types.InfoType;
import net.minecraft.server.v1_7_R4.*;
import org.bitterorange.flansmodslain.minecraft.Minecraft;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R4.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.flansmod.common.guns.type.BulletType.bullets;
import static com.flansmod.common.guns.type.GrenadeType.grenades;
import static org.bitterorange.flansmodslain.FlansModSlain.PluginRoot;
import static org.bitterorange.flansmodslain.listeners.PlayerSlainListener.*;

/**
 * 通过反射技术提供了在插件层面访问FlansMod和MCHeli的一套方法
 * 其他插件通过调用FlansModAPI，可轻松操作Forge模组底层的一些方法
 */
public class FlansModAPI {

    public static Map<String, String> vehicleWeaponNameMap = new HashMap<>();

    static {
        loadVehicleWeaponNameMap();
    }

    private static void loadVehicleWeaponNameMap() {
        try {
            File file = new File(PluginRoot, "vehicle-weapons.yml");
            if (!file.exists()) {
                file.mkdir();
            }
            Map<String, String> map = new Yaml().loadAs(Files.newInputStream(file.toPath()), Map.class);
            if (map != null) {
                vehicleWeaponNameMap.putAll(map);
            }
            System.out.println(vehicleWeaponNameMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean isFlanVehicle(org.bukkit.entity.Player p) {
        return SoldierAPI.isFlanVehicle(((CraftPlayer) p).getHandle());
    }

    public static String getFlanVehicleName(org.bukkit.entity.Player p) {
        return SoldierAPI.getVehicleName(((CraftPlayer) p).getHandle());
    }

    public static String getFlanVehicleShortName(org.bukkit.entity.Player p) {
        return SoldierAPI.getVehicleShortName(((CraftPlayer) p).getHandle());
    }

    /**
     * 获取玩家乘坐的MCH载具
     *
     * @param p 玩家
     * @return 载具
     */
    public static String getPlayerVehicle(org.bukkit.entity.Player p) {
        String originName = p.getVehicle().getType().name();
        if (!originName.startsWith("MCHELI_")) {
            return "AIR";
        };
        if (originName.contains("UAV")) {
            return getUAV(p);
        } else if (originName.contains("GLTD")) {
            return "SOFLAM";
        } else if (originName.contains("SEAT")) {
            return "PASSENGER";
        } else {
            try {
                EntityPlayer entityPlayer = ((CraftPlayer) p).getHandle();
                Entity vehicle = entityPlayer.vehicle;
                Object info = vehicle.getClass().getMethod("getAcInfo").invoke(vehicle);
                HashMap<?, ?> map = (HashMap<?, ?>) info.getClass().getField("displayNameLang").get(info);
                return map.get("en_US") == null ? "AIR" : (String) map.get("en_US");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return "AIR";
    }

    public static List<String[]> getVehicleWeapons(org.bukkit.entity.Player p) {
        return MCHeliUtil.getWeapons(((CraftPlayer) p).getHandle());
    }

    public static List<String> getDisplayedVehicleWeapons(org.bukkit.entity.Player p) {
        List<String[]> list = MCHeliUtil.getWeapons(((CraftPlayer) p).getHandle());
        if(list == null) return new ArrayList<>();
        List<String> weapons = new ArrayList<>(4);
        for (String[] weapon : list) {
            if (weapons.size() < 4 && weapon.length > 0 && !"none".equals(weapon[0])) {
                if (vehicleWeaponNameMap.containsKey(weapon[0])) {
                    weapons.add(vehicleWeaponNameMap.get(weapon[0]));
                } else {
                    weapons.add(weapon[0]);
                }
            }
        }
        return weapons;
    }

    public static String nameOfWeapon(Material weapon) {
        String bukkitName = weapon.toString();
        if (bukkitName.startsWith("FLANSMOD_")) {
            try {
                Object item = Minecraft.getItemById(weapon.getId());
                InfoType infoType = (InfoType) item.getClass().getField("type").get(item);
                return infoType.name;
            } catch (Exception e) {
                e.printStackTrace();
                return weapon.toString();
            }
        } else if (bukkitName.startsWith("MCHELI_")) {
            switch (weapon.toString()) {
                case "MCHELI_FIM92":
                    return "FIM-92 Stringer";
                case "MCHELI_FGM148":
                    return "FGM-148 Javelin";
                case "MCHELI_WRENCH":
                    return "WRENCH";
            }
            return weapon.toString();
        } else {
            return weapon.toString();
        }
    }

    public static boolean isMCHeliUAV(org.bukkit.entity.Entity entity) {
        return MCHeliUtil.isMCHeliUAV(((CraftEntity) entity).getHandle());
    }

    public static boolean isEnemyUAV(org.bukkit.entity.Entity entity, org.bukkit.entity.Player placer) {
        return MCHeliUtil.isEnemyUAV(((CraftEntity) entity).getHandle(), ((CraftPlayer) placer).getHandle());
    }

    public static boolean isOnlineUAV(org.bukkit.entity.Entity entity) {
        for (org.bukkit.entity.Entity p : entity.getWorld().getEntities()) {
            if (p instanceof Player && p.getVehicle() != null && p.getVehicle().getType().name().contains("UAV")) {
                EntityPlayer entityPlayer = ((CraftPlayer) p).getHandle();
                Entity vehicle = entityPlayer.vehicle;
                Entity uav = (Entity) MCHeliUtil.getUavLastControlAircraft(vehicle);
                if (uav.getId() == entity.getEntityId()) return true;
            }
        }
        return false;
    }

    public static String getUAV(Player p) {
        try {
            EntityPlayer entityPlayer = ((CraftPlayer) p).getHandle();
            Entity vehicle = entityPlayer.vehicle;
            Entity uav = (Entity) MCHeliUtil.getUavLastControlAircraft(vehicle);
            if (uav == null) return "UAV";
            Object info = uav.getClass().getMethod("getAcInfo").invoke(uav);
            HashMap<?, ?> map = (HashMap<?, ?>) info.getClass().getField("displayNameLang").get(info);
            return map.get("en_US") == null ? "AIR" : (String) map.get("en_US");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "UAV";
    }

    public static void markEntity(Player p, int time, org.bukkit.entity.Entity entity) {
        MCHeliUtil.sendSpotedEntityListToSameTeam(((CraftPlayer) p).getHandle(), time, new int[]{entity.getEntityId()});
    }

    public static void markEntity(Player p, int time, List<org.bukkit.entity.Entity> entities) {
        MCHeliUtil.sendSpotedEntityListToSameTeam(((CraftPlayer) p).getHandle(), time, entities.stream().mapToInt(org.bukkit.entity.Entity::getEntityId).toArray());
    }

    public static void markPlayer(Player p, int time, List<Player> entities) {
        MCHeliUtil.sendSpotedEntityListToSameTeam(((CraftPlayer) p).getHandle(), time, entities.stream().mapToInt(Player::getEntityId).toArray());
    }

    public static boolean isSoldier(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return SoldierAPI.isSoldier(entity);
    }

    public static boolean isPlayer(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return SoldierAPI.isPlayer(entity);
    }

    public static void spawnAI(org.bukkit.World world, int x, int y, int z, Player player) {
        SoldierAPI.spawnAI(((CraftWorld) world).getHandle(), x, y, z, ((CraftPlayer) player).getHandle());
    }

    public static void spawnAI(org.bukkit.World world, int x, int y, int z, String teamName) {
        SoldierAPI.spawnAI(((CraftWorld) world).getHandle(), x, y, z, teamName);
    }

    public static void spawnCorpse(org.bukkit.World world, double x, double y, double z, Player player) {
        SoldierAPI.spawnCorpse(((CraftWorld) world).getHandle(), x, y, z, ((CraftPlayer) player).getHandle());
    }

    public static List<Integer> getNearByAiId(org.bukkit.World world, double x, double y, double z, int radius) {
        World minecraftWorld = ((CraftWorld) world).getHandle();
        return SoldierAPI.getNearByAiId(minecraftWorld, x, y, z, radius);
    }

    public static void setMoveTo(int entityId, double x, double y, double z) {
        Object o = SoldierAPI.getSoldier(entityId);
        if (o != null) {
            SoldierAPI.setMoveTo(o, x, y, z, false);
        }
    }

    public static boolean isAiTeamer(Player p, int aiId) {
        Object ai = SoldierAPI.getSoldier(aiId);
        if (ai == null) return false;
        String aiTeam = SoldierAPI.getSoldierTeamName(ai);
        String playerTeam = p.getScoreboard().getPlayerTeam(p).getName();
        return aiTeam.equals(playerTeam);
    }

    public static void destroyAllAI(org.bukkit.World w) {
        SoldierAPI.destroyAllAI(((CraftWorld) w).getHandle());
    }

    public static boolean isBreakableBlock(org.bukkit.block.Block block) {
        Block nmsBlock = ((CraftWorld) block.getWorld()).getHandle().getType(block.getX(), block.getY(), block.getZ());
        return BlockAPI.isBreakableBlock(nmsBlock);
    }

    public static boolean canBeBrokenByExplosion(org.bukkit.block.Block block) {
        Block nmsBlock = ((CraftWorld) block.getWorld()).getHandle().getType(block.getX(), block.getY(), block.getZ());
        return BlockAPI.canBeBrokenByExplosion(nmsBlock);
    }


    public static boolean canBeBrokenByPlayer(org.bukkit.block.Block block) {
        Block nmsBlock = ((CraftWorld) block.getWorld()).getHandle().getType(block.getX(), block.getY(), block.getZ());
        return BlockAPI.canBeBrokenByPlayer(nmsBlock);
    }


    public static void spawnBullet(org.bukkit.World bukkitWorld, org.bukkit.entity.Player shooter, String shortName, double posX, double posY, double posZ, double vecX, double vecY, double vecZ) {
        try {
            World minecraftWorld = ((CraftWorld) bukkitWorld).getHandle();
            EntityLiving entityPlayer = ((CraftPlayer) shooter).getHandle();
            Object bulletType = FlansModBulletType.getMethod("getBullet").invoke(shortName);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void spawnGrenade(org.bukkit.World bukkitWorld, String shortName, org.bukkit.entity.Player shooter) {
        try {
            World minecraftWorld = ((CraftWorld) bukkitWorld).getHandle();
            EntityLiving entityPlayer = ((CraftPlayer) shooter).getHandle();
            GrenadeType grenadeType = getGrenade(shortName);
            Entity entity = (Entity) FlansModGrenade.getConstructor(WorldClass, FlansModGrenadeType, EntityLivingBaseClass).newInstance(minecraftWorld, grenadeType, entityPlayer);
            minecraftWorld.addEntity(entity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void spawnGrenade(org.bukkit.World bukkitWorld, String shortName, org.bukkit.entity.Player shooter, double x, double y, double z) {
        try {
            World minecraftWorld = ((CraftWorld) bukkitWorld).getHandle();
            EntityLiving entityPlayer = ((CraftPlayer) shooter).getHandle();
            GrenadeType grenadeType = getGrenade(shortName);
            Entity entity = (Entity) FlansModGrenade.getConstructor(WorldClass, FlansModGrenadeType, EntityLivingBaseClass, double.class, double.class, double.class).newInstance(minecraftWorld, grenadeType, entityPlayer, x, y, z);
            minecraftWorld.addEntity(entity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static BulletType getBullet(String s) {
        for (BulletType bullet : bullets) {
            if (bullet.shortName.equals(s))
                return bullet;
        }
        return null;
    }

    public static GrenadeType getGrenade(String s) {
        for (GrenadeType grenade : grenades) {
            if (grenade.shortName.equals(s))
                return grenade;
        }
        return null;
    }

    public static String getSoldierFaction(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return SoldierAPI.getSoldierFaction(entity);
    }

    public static String getSoldierTeamName(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return SoldierAPI.getSoldierTeamName(entity);
    }

    public static String getSoldierName(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return SoldierAPI.getSoldierName(entity);
    }

    public static ItemStack getSoliderHeldItem(org.bukkit.entity.Entity e) {
        Entity entity = ((CraftEntity) e).getHandle();
        return CraftItemStack.asBukkitCopy((net.minecraft.server.v1_7_R4.ItemStack) SoldierAPI.getHeldItem(entity));
    }
}
